﻿using BlockeyEssentials.Geometry;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace BlockeyEssentials.Camera
{
    public class Camera2D
    {

        public Camera2D(Vector2 oStartPos)
        {
            _Position = oStartPos;
            _PositionTarget = oStartPos;
            _PositionSpeed = 0.05f;

            _Zoom = 1.0f;
            _ZoomTarget = 1.0f;
            _ZoomSpeed = 0.1f;

            _Rotation = 0.0f;
            _RotationTarget = 0.0f;
            _RotationSpeed = 0.1f;

            _DebugCircleTexture = All.Texture_Circle;
        }

        #region Methods

        public void Update(Vector2 oFocus)
        {
            //// -- Position -- ////
            PositionTarget = oFocus;
            Position = Vector2.Lerp(Position, PositionTarget, PositionSpeed);

            //// -- Zoom -- ////
            Zoom = MathHelper.Lerp(Zoom, ZoomTarget, ZoomSpeed);

            //// -- Rotation -- ////
            Rotation = MathHelper.Lerp(Rotation, RotationTarget, RotationSpeed);
        }

        /// <summary>
        /// Gives the 3D Transformation Matrix for the Camera;
        /// </summary>
        /// <param name="graphicsDevice">The Main Graphics Device</param>
        /// <returns></returns>
        public Matrix GetTransformation(GraphicsDevice graphicsDevice)
        {
            var oWidth = All.Resolution.Width;
            var oHeight = All.Resolution.Height;

            _TransformationMatrix =       // Thanks to o KB o for this solution
                Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0)) *
                Matrix.CreateRotationZ(Rotation) *
                Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
                Matrix.CreateTranslation(new Vector3(oWidth * 0.5f, oHeight * 0.5f, 0));

            return _TransformationMatrix;
        }

        /// <summary>
        /// Draws the location of the Position and Target for Debugging
        /// </summary>
        public void DrawTarget(SpriteBatch oSB)
        {
            Circle oCircle;

            //// -- Draws Position -- ////
            oCircle = new Circle(Position, 10);
            oCircle.Draw(oSB, Color.Red, _DebugCircleTexture, 0.98f);

            //// -- Draws Position Target -- ////
            oCircle = new Circle(PositionTarget, 5);
            oCircle.Draw(oSB, Color.Black, _DebugCircleTexture, 1.00f);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets and Sets the Position
        /// </summary>
        public Vector2 Position
        {
            get { return _Position; }
            private set { _Position = value; }
        }

        /// <summary>
        /// Gets and Sets the Position Target
        /// </summary>
        public Vector2 PositionTarget
        {
            get { return _PositionTarget; }
            set { _PositionTarget = value; }
        }

        /// <summary>
        /// Gets and Sets the Zoom Speed
        /// </summary>
        public float PositionSpeed
        {
            get { return _PositionSpeed; }
            set
            {
                _PositionSpeed = value;
                if (_PositionSpeed < 0)
                    _PositionSpeed = 0;
            }
        }

        /// <summary>
        /// Gets and Sets the Zoom
        /// </summary>
        public float Zoom
        {
            get { return _Zoom; }
            private set
            {
                _Zoom = value;
                if (_Zoom < 0.1f)
                    _Zoom = 0.1f;
            }
        }

        /// <summary>
        /// Gets and Sets the Zoom Target
        /// </summary>
        public float ZoomTarget
        {
            get { return _ZoomTarget; }
            set
            {
                _ZoomTarget = value;
                if (_ZoomTarget < 0.1f)
                    _ZoomTarget = 0.1f;
            }
        }

        /// <summary>
        /// Gets and Sets the Zoom Speed
        /// </summary>
        public float ZoomSpeed
        {
            get { return _ZoomSpeed; }
            set
            {
                _ZoomSpeed = value;
                if (_ZoomSpeed < 0)
                    _ZoomSpeed = 0;
            }
        }

        /// <summary>
        /// Gets and Sets the Rotation
        /// </summary>
        public float Rotation
        {
            get { return _Rotation; }
            private set { _Rotation = value; }
        }

        /// <summary>
        /// Gets and Sets the Rotation Target
        /// </summary>
        public float RotationTarget
        {
            get { return _RotationTarget; }
            set { _RotationTarget = value; }
        }

        /// <summary>
        /// Gets and Sets the Zoom Speed
        /// </summary>
        public float RotationSpeed
        {
            get { return _RotationSpeed; }
            set
            {
                _RotationSpeed = value;
                if (_RotationSpeed < 0)
                    _RotationSpeed = 0;
            }
        }

        public Matrix TransformationMatrix
        {
            get { return _TransformationMatrix; }
            set { _TransformationMatrix = value; }
        }

        #endregion

        private Vector2 _Position;
        private Vector2 _PositionTarget;
        private float _PositionSpeed;

        private float _Zoom;
        private float _ZoomTarget;
        private float _ZoomSpeed;

        private float _Rotation;
        private float _RotationTarget;
        private float _RotationSpeed;

        private Matrix _TransformationMatrix;

        private Texture2D _DebugCircleTexture;

        //Spritebatch Draw Method
        //spriteBatch.Begin(SpriteSortMode.BackToFront,
        //                BlendState.AlphaBlend,
        //                null,
        //                null,
        //                null,
        //                null,
        //                cam.get_transformation(device /*Send the variable that has your graphic device here*/)

    }
}
